package com.sc.nft.helper;

import cn.com.sand.ceas.sdk.CeasHttpUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.sc.nft.config.sand.SandConfig;
import com.sc.nft.dao.*;
import com.sc.nft.entity.*;
import com.sc.nft.entity.dto.SaasTaskBurialPointDTO;
import com.sc.nft.entity.dto.UserAffirmDTO;
import com.sc.nft.entity.dto.sand.SmsDTO;
import com.sc.nft.entity.vo.BalanceVO;
import com.sc.nft.enums.*;
import com.sc.nft.exception.GlobalRunTimeException;
import com.sc.nft.service.UserWalletService;
import com.sc.nft.util.BankCardUtil;
import com.sc.nft.util.OrderNoUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import sun.misc.BASE64Encoder;

import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.Date;

@Component
@RequiredArgsConstructor
@Slf4j
public class SandAccountHelper {

    private final IdcardInfoDao idcardInfoDao;
    private final UserInfoDao userInfoDao;
    private final UserWalletDao userWalletDao;
    private final UserWalletService userWalletService;
    private final UserWalletDetailDao userWalletDetailDao;
    private final WithdrawBankCardDao withdrawBankCardDao;
    private final PayOrderDao payOrderDao;
    private final StaticDataDao staticDataDao;
    private final HfPayHelper hfPayHelper;
    private final LlPayHelper llPayHelper;
    private final HnaPayHelper hnaPayHelper;
    private final HfTransDao hfTransDao;
    private final HfTransDetailDao hfTransDetailDao;
    private final MessageQueueHelper messageQueueHelper;


    @Value("${pay.sandConfig.withdraw.notify_url}")
    private String withdrawNotify;
    @Value("${pay.sandConfig.recharge.notify_url}")
    private String rechargeNotify;
    @Value("${pay.sandConfig.protocol.notify_url}")
    private String protocolNotify;
    @Value("${pay.sandConfig.pwd.notify_url}")
    private String pwdNotify;
    @Value("${pay.sandConfig.cancel.notify_url}")
    private String cancelNotify;
    @Value("${spring.profiles.active}")
    private String active;
    @Value("${pay.wallet.wallet_url}")
    private String walletUrl;


    private final static BigDecimal LOW_FEE = BigDecimal.valueOf(2);//最低手续费

    /**
     * 开户
     *
     * @param customerOrderNo
     * @param smsCode
     * @param smsSerialNo
     * @param frontImgNo
     * @param reverseImgNo
     */
    public void sandOpenAccount(String customerOrderNo, UserInfo userInfo, String smsCode, String smsSerialNo, String frontImgNo, String reverseImgNo) {
        IdcardInfo idcardInfo = idcardInfoDao.findLastOneByUserIdAndIsPass(userInfo.getId());
        JSONObject param = new JSONObject();
        param.put("customerOrderNo", customerOrderNo); //商户订单号 需要和发送短信订单号一致
        param.put("bizUserNo", userInfo.getSandWithdrawUuid()); //会员编号
        param.put("nickName", userInfo.getNickName()); //昵称
        param.put("mobile", userInfo.getUserTel()); //手机号码
        param.put("name", idcardInfo.getName()); //客户姓名
        param.put("idType", "01"); //证件类型 01:身份证
        param.put("idNo", idcardInfo.getCardId()); //证件号码
        param.put("smsCode", smsCode); //短信验证码
        param.put("smsSerialNo", smsSerialNo); //短信验证码流水号
        JSONObject idImgList = new JSONObject();
        idImgList.put("frontImgNo", frontImgNo); //国徽面文件编号
        idImgList.put("reverseImgNo", reverseImgNo); //人脸面文件编号
        param.put("idImgList", idImgList); //身份证附件
        JSONObject result = invoke(userInfo.getId(), param, SandMethodEnum.CEAS_ACCOUNT_REGISTER_OPEN_SERVER);
        if (StrUtil.equals(result.getString("responseCode"), "00000")) {
            userInfoDao.openAccountSuccess(userInfo.getId(), result.getString("masterAccount"));
            SaasTaskBurialPointDTO saasTaskBurialPointDTO = new SaasTaskBurialPointDTO();
            // 开户成功之后,发送任务判定
            messageQueueHelper.sendMessage(MessageTopic.DISK_TAKER, saasTaskBurialPointDTO.wallet(userInfo.getId(), SaasTaskTypeEnum.OPEN_WALLET_FOR_THE_FIRST_TIME, BigDecimal.ONE, 1, null), SaasTaskTypeEnum.OPEN_WALLET_FOR_THE_FIRST_TIME.name());
            // 开户成功之后,发送任务判定
            messageQueueHelper.sendMessage(MessageTopic.DISK_TAKER, saasTaskBurialPointDTO.wallet(userInfo.getId(), SaasTaskTypeEnum.FIRST_TIME_OPEN_WALLET_INVITATION, BigDecimal.ONE, 1, null), SaasTaskTypeEnum.FIRST_TIME_OPEN_WALLET_INVITATION.name());

        } else {
            throw new GlobalRunTimeException("开户失败:" + result.getString("responseDesc"));
        }
    }


    /**
     * 发送短信
     *
     * @param userInfo
     */
    public SmsDTO smsSend(UserInfo userInfo) {
        JSONObject param = new JSONObject();
        param.put("customerOrderNo", OrderNoUtil.getOrderNo());//商户订单号
        param.put("bizUserNo", userInfo.getSandWithdrawUuid());//会员编号
        param.put("mobile", userInfo.getUserTel());
        param.put("bizScene", "01");//业务场景号：01：开户
        JSONObject result = invoke(userInfo.getId(), param, SandMethodEnum.CEAS_SERVER_SMS_SEND);
        if (StrUtil.equals(result.getString("responseCode"), "00000")) {
            SmsDTO smsDTO = new SmsDTO();
            smsDTO.setSmsSerialNo(result.getString("smsSerialNo"));
            smsDTO.setCustomerOrderNo(result.getString("customerOrderNo"));
            return smsDTO;
        } else {
            throw new GlobalRunTimeException("发送短信失败:" + result.getString("responseDesc"));
        }
    }

    /**
     * 上传附件
     *
     * @param userInfo
     * @param type
     * @param file
     * @return
     */
    public String upload(UserInfo userInfo, String type, MultipartFile file) {
        JSONObject param = new JSONObject();
        param.put("customerOrderNo", OrderNoUtil.getOrderNo()); //商户订单号
        param.put("bizUserNo", userInfo.getSandWithdrawUuid()); //会员编号
        param.put("fileContent", GetImageStr(file)); // 附件base64
        param.put("fileType", type); //附件类型 01—身份证国徽面 02—身份证人像面
        JSONObject result = invoke(userInfo.getId(), param, SandMethodEnum.CEAS_ELEC_PAPERS_UPLOAD);
        if (StrUtil.equals(result.getString("responseCode"), "00000")) {
            return result.getString("fileNo");
        } else {
            throw new GlobalRunTimeException("附件上传失败:" + result.getString("responseDesc"));
        }
    }


    /**
     * 签约协议
     *
     * @param userInfo
     * @return
     */
    public String sign(UserInfo userInfo) {
        JSONObject param = new JSONObject();
        param.put("customerOrderNo", OrderNoUtil.getOrderNo()); //商户订单号
        param.put("bizUserNo", userInfo.getSandWithdrawUuid()); //会员编号
        JSONObject protocol = new JSONObject();
        protocol.put("protocolNo", "XY001");
        param.put("signProtocol", protocol.toJSONString());
        param.put("frontUrl", SandConfig.FAST_RETURN_URL);
        param.put("notifyUrl", protocolNotify);
        JSONObject result = invoke(userInfo.getId(), param, SandMethodEnum.CEAS_ELEC_ACCOUNT_PROTOCOL_SIGN);
        if (StrUtil.equals(result.getString("responseCode"), "00000")) {
            return result.getString("url");
        } else {
            throw new GlobalRunTimeException("附件上传失败:" + result.getString("responseDesc"));
        }
    }

    /**
     * 查询绑卡结果
     *
     * @param userInfo
     * @return
     */
    public String queryBindCard(UserInfo userInfo) {
        JSONObject param = new JSONObject();
        param.put("customerOrderNo", OrderNoUtil.getOrderNo()); //商户订单号
        param.put("bizUserNo", userInfo.getSandWithdrawUuid()); //会员编号
        JSONObject result = invoke(userInfo.getId(), param, SandMethodEnum.CEAS_ELEC_BIND_CARD_QUERY);
        return result.toJSONString();
    }

    /**
     * 绑卡
     *
     * @param userInfo
     * @param cardNo
     * @param identityNo
     * @param name
     * @param phoneNo
     */
    public void bindCard(UserInfo userInfo, String cardNo, String identityNo, String name, String phoneNo) {
        WithdrawBankCard userCard = withdrawBankCardDao.findUserCard(userInfo.getId(), cardNo, WalletChannelEnum.SAND);
        if (ObjectUtil.isNotNull(userCard)) {
            throw new GlobalRunTimeException("该银行卡已经绑定过了");
        }
        JSONObject param = new JSONObject();
        param.put("customerOrderNo", OrderNoUtil.getOrderNo()); //商户订单号 不能重复
        param.put("bizUserNo", userInfo.getSandWithdrawUuid()); //会员编号
        param.put("cardNo", cardNo); //卡号
        param.put("bankMobile", phoneNo); //银行预留手机号
        param.put("relatedCardType", "01"); //绑卡类型 01：提现卡（默认）02:快捷充值+提现卡
        JSONObject result = invoke(userInfo.getId(), param, SandMethodEnum.CEAS_ELEC_BIND_CARD);
        log.info("绑卡返回数据:{}", result);
        if (StrUtil.equals(result.getString("responseCode"), "00000")) {
//            BankDetails bankDetails = bankDetailsDao.getById(bankId);
//            if(ObjectUtil.isEmpty(bankDetails)){
//                throw new GlobalRunTimeException("暂时不支持该银行卡绑定");
//            }
            userCard = new WithdrawBankCard();
            userCard.setUserId(userInfo.getId());
//            userCard.setBankId(bankId);
            userCard.setBankName(BankCardUtil.getBankNameByCardNo(cardNo));
//            userCard.setBankIcon(bankDetails.getBankIcon());
            userCard.setBankCardNo(cardNo);
            userCard.setChannel(WalletChannelEnum.SAND);
            userCard.setRelatedCardNo(result.getString("relatedCardNo"));
            userCard.setName(name);
            userCard.setMobile(phoneNo);
            userCard.setIdentityNo(identityNo);
            userCard.setStatus(true);
            userCard.insert();
        } else {
            throw new GlobalRunTimeException("绑卡失败:" + result.getString("responseDesc"));
        }
    }

    /**
     * 转帐中金额
     *
     * @param sandTransferRecord
     */
    public void hfTransfer(UserInfo userInfo, SandTransferRecord sandTransferRecord) {
        switch (sandTransferRecord.getChannel()) {
            case SAND:
                break;
            case HF:
                BigDecimal lastAmount = hfTransDao.getSumLastAmount();
                BigDecimal withdrawAmount = sandTransferRecord.getAmount();
                if (NumberUtil.isGreaterOrEqual(lastAmount, sandTransferRecord.getAmount())) {
                    BigDecimal historyAmount = hfTransDetailDao.getHistoryAmount(sandTransferRecord.getId());
                    withdrawAmount = withdrawAmount.subtract(historyAmount);
                    BigDecimal thisTimeAmount = BigDecimal.ZERO;
                    while (NumberUtil.isGreater(withdrawAmount, BigDecimal.ZERO)) {
                        HfTrans firstOne = hfTransDao.getFirstOne();
                        if (NumberUtil.isGreater(firstOne.getLastTransAmount(), withdrawAmount)) {
                            thisTimeAmount = withdrawAmount;
                            firstOne.setAlreadyTransAmount(firstOne.getAlreadyTransAmount().add(withdrawAmount));
                            withdrawAmount = BigDecimal.ZERO;
                        } else {
                            withdrawAmount = withdrawAmount.subtract(firstOne.getLastTransAmount());
                            thisTimeAmount = firstOne.getLastTransAmount();
                            firstOne.setAlreadyTransAmount(firstOne.getAlreadyTransAmount().add(firstOne.getLastTransAmount()));
                        }
                        firstOne.setLastTransAmount(firstOne.getLastTransAmount().subtract(thisTimeAmount));
                        HfTransDetail hfTransDetail = new HfTransDetail();
                        hfTransDetail.setTransId(firstOne.getId());
                        hfTransDetail.setUserId(userInfo.getId());
                        hfTransDetail.setOrderNo(OrderNoUtil.getOrderNo());
                        hfTransDetail.setTransferId(sandTransferRecord.getId());
                        hfTransDetail.setAmount(thisTimeAmount);
                        hfPayHelper.splitMoney(userInfo.getId(), payOrderDao.getById(firstOne.getPayOrderId()), firstOne, hfTransDetail);
                        hfTransDetail.insert();

                        if (NumberUtil.isLessOrEqual(firstOne.getLastTransAmount(), BigDecimal.ZERO)) {
                            firstOne.setStatus(false);
                        }
                        firstOne.updateById();

                    }
                    sandTransferRecord.setApprovalStatus(1);
                    sandTransferRecord.setDealTime(new Date());
                    sandTransferRecord.setFeeAmount("0");
                    sandTransferRecord.setWithdrawStatus(1);
                    sandTransferRecord.updateById();
                    userWalletDao.transferSuccess(userInfo.getId(), sandTransferRecord.getAmount());
//                    UserWallet userWallet = userWalletDao.getByUserId(userInfo.getId());
//                    //添加钱包明细
//                    UserWalletDetail userWalletDetail = new UserWalletDetail();
//                    userWalletDetail.setUserId(userInfo.getId());
//                    userWalletDetail.setType(WalletDetailTypeEnum.TRANSFER_HUIFU);
//                    userWalletDetail.setAmount(sandTransferRecord.getAmount());
//                    userWalletDetail.setCharge(BigDecimal.ZERO);
//                    userWalletDetail.setRealAmount(sandTransferRecord.getAmount());
//                    userWalletDetail.setAfterBalance(userWallet.getBalance());
//                    userWalletDetail.setBeforeBalance(userWallet.getBalance().add(sandTransferRecord.getAmount()));
//                    userWalletDetail.setIsAdd(Boolean.FALSE);
//                    userWalletDetail.insert();
                } else {
                    JSONObject transfer = hfPayHelper.transfer(userInfo.getId(), sandTransferRecord.getAmount());
                    sandTransferRecord.setApprovalStatus(1);
                    sandTransferRecord.setDealTime(new Date());
                    sandTransferRecord.setFeeAmount(transfer.getString("fee_amt"));
                    sandTransferRecord.setWithdrawStatus(1);
                    sandTransferRecord.updateById();
                    userWalletDao.transferSuccess(userInfo.getId(), sandTransferRecord.getAmount());
//                    UserWallet userWallet = userWalletDao.getByUserId(userInfo.getId());
                    //添加钱包明细
//                    UserWalletDetail userWalletDetail = new UserWalletDetail();
//                    userWalletDetail.setUserId(userInfo.getId());
//                    userWalletDetail.setType(WalletDetailTypeEnum.TRANSFER_HUIFU);
//                    userWalletDetail.setAmount(sandTransferRecord.getAmount());
//                    userWalletDetail.setCharge(BigDecimal.ZERO);
//                    userWalletDetail.setRealAmount(sandTransferRecord.getAmount());
//                    userWalletDetail.setAfterBalance(userWallet.getBalance());
//                    userWalletDetail.setBeforeBalance(userWallet.getBalance().add(sandTransferRecord.getAmount()));
//                    userWalletDetail.setIsAdd(Boolean.FALSE);
//                    userWalletDetail.insert();
                }


                break;
            case LL:

                break;
        }

    }


    /**
     * 转帐中金额
     *
     * @param sandTransferRecord
     */
    @Transactional(rollbackFor = Exception.class)
    public void transfer(UserInfo userInfo, SandTransferRecord sandTransferRecord) {

        switch (sandTransferRecord.getChannel()) {
            case SAND:
                JSONObject param = new JSONObject();
                param.put("customerOrderNo", sandTransferRecord.getCustomerOrderNo());
                param.put("accountType", "01"); //账户类型 01：支付电子户 02：宝易付权益电子户
                param.put("orderAmt", sandTransferRecord.getAmount().toPlainString());//订单金额 以元为单位 15位数字，保留两位小数
                JSONObject accountInfo = new JSONObject();
                accountInfo.put("bizUserNo", userInfo.getSandWithdrawUuid());
                IdcardInfo idcardInfo = idcardInfoDao.getByUserIdAndIsPass(userInfo.getId());
                accountInfo.put("name", idcardInfo.getName());
                param.put("payee", accountInfo);//收款方
                JSONObject result = invoke(userInfo.getId(), param, SandMethodEnum.CEAS_SERVER_TRANSFER_CORP);
                if (StrUtil.equals(result.getString("responseCode"), "00000")) {
                    if (StrUtil.equals(result.getString("orderStatus"), "00")) {
                        sandTransferRecord.setApprovalStatus(1);
                        sandTransferRecord.setDealTime(new Date());
                        sandTransferRecord.setFeeAmount(result.getString("feeAmt"));
                        sandTransferRecord.setWithdrawStatus(1);
                        sandTransferRecord.updateById();
                        userWalletDao.transferSuccess(userInfo.getId(), sandTransferRecord.getAmount());

                    } else if (StrUtil.equals(result.getString("orderStatus"), "01")) {
                        sandTransferRecord.setApprovalStatus(1);
                        sandTransferRecord.setFeeAmount(result.getString("feeAmt"));
                        sandTransferRecord.setWithdrawStatus(0);
                        sandTransferRecord.updateById();
                    } else if (StrUtil.equals(result.getString("orderStatus"), "02")) {
                        sandTransferRecord.setApprovalStatus(2);
                        sandTransferRecord.setFeeAmount(result.getString("feeAmt"));
                        sandTransferRecord.setWithdrawStatus(2);
                        sandTransferRecord.updateById();
                        userWalletService.transferFail(userInfo.getId(), sandTransferRecord.getAmount());
                    }
                } else {
                    sandTransferRecord.setRemark(result.getString("responseDesc"));
                    sandTransferRecord.updateById();
                    log.error("转账失败:" + result.getString("responseDesc"));
                }
                break;
            case HF:
                throw new GlobalRunTimeException("请联系管理员");//不应该能走到这里
            case LL:
                JSONObject transfer = llPayHelper.transfer(userInfo, sandTransferRecord);
                sandTransferRecord.setApprovalStatus(1);
                sandTransferRecord.setDealTime(new Date());
                sandTransferRecord.setFeeAmount(transfer.getString("fee_amt"));
                sandTransferRecord.setWithdrawStatus(1);
                sandTransferRecord.updateById();
                userWalletDao.transferSuccess(userInfo.getId(), sandTransferRecord.getAmount());
                break;
            case HNA:
                JSONObject hna = hnaPayHelper.transfer(userInfo, sandTransferRecord.getAmount().toString());
                sandTransferRecord.setApprovalStatus(1);
                sandTransferRecord.setDealTime(new Date());
                sandTransferRecord.setFeeAmount("0");
                sandTransferRecord.setWithdrawStatus(1);
                sandTransferRecord.updateById();
                userWalletDao.transferSuccess(userInfo.getId(), sandTransferRecord.getAmount());
                break;
        }

    }

    @Transactional(rollbackFor = Exception.class)
    public void checkWithdraw(SandWithdrawRecord sandWithdrawRecord) {
        JSONObject param = new JSONObject();
        param.put("customerOrderNo", OrderNoUtil.getOrderNo());//商户订单号
        param.put("oriCustomerOrderNo", sandWithdrawRecord.getCustomerOrderNo());//原交易订单号
//        param.put("oriPayeeCustomerOrderNo", "");//原交易子订单号
        JSONObject result = invoke(sandWithdrawRecord.getUserId(), param, SandMethodEnum.CEAS_SERVER_TRANS_INFO_QUERY);
        if (StrUtil.equals(result.getString("responseCode"), "00000")) {
            if (StrUtil.equals(result.getString("orderStatus"), "03") || StrUtil.equals(result.getString("orderStatus"), "02") || StrUtil.equals(result.getString("orderStatus"), "04")) {
                sandWithdrawRecord.setRemark("未输入交易密码");
                sandWithdrawRecord.setStatus(2);
                sandWithdrawRecord.updateById();
            }
            if (StrUtil.equals(result.getString("orderStatus"), "00") && StrUtil.equals(result.getString("withdrawStatus"), "02")) {
                sandWithdrawRecord.setRemark(result.getString("failureMsgs"));
                sandWithdrawRecord.setStatus(2);
                sandWithdrawRecord.updateById();
            }
        }
    }


    @Transactional(rollbackFor = Exception.class)
    public void checkTransfer(SandTransferRecord sandTransferRecord) {
        JSONObject param = new JSONObject();
        param.put("customerOrderNo", OrderNoUtil.getOrderNo());//商户订单号
        param.put("oriCustomerOrderNo", sandTransferRecord.getCustomerOrderNo());//原交易订单号
//        param.put("oriPayeeCustomerOrderNo", "");//原交易子订单号
        JSONObject result = invoke(sandTransferRecord.getUserId(), param, SandMethodEnum.CEAS_SERVER_TRANS_INFO_QUERY);
        if (StrUtil.equals(result.getString("responseCode"), "00000")) {
            if (StrUtil.equals(result.getString("orderStatus"), "00")) {
                sandTransferRecord.setApprovalStatus(1);
                sandTransferRecord.setDealTime(new Date());
                sandTransferRecord.setFeeAmount(result.getString("feeAmt"));
                sandTransferRecord.setWithdrawStatus(1);
                sandTransferRecord.updateById();
                userWalletDao.transferSuccess(sandTransferRecord.getUserId(), sandTransferRecord.getAmount());
                UserWallet userWallet = userWalletDao.getByUserId(sandTransferRecord.getUserId());
                //添加钱包明细
                UserWalletDetail userWalletDetail = new UserWalletDetail();
                userWalletDetail.setUserId(sandTransferRecord.getUserId());
                userWalletDetail.setType(WalletDetailTypeEnum.TRANSFER_SAND);
                userWalletDetail.setAmount(sandTransferRecord.getAmount());
                userWalletDetail.setCharge(BigDecimal.ZERO);
                userWalletDetail.setRealAmount(sandTransferRecord.getAmount());
                userWalletDetail.setAfterBalance(userWallet.getBalance());
                userWalletDetail.setBeforeBalance(userWallet.getBalance().add(sandTransferRecord.getAmount()));
                userWalletDetail.setIsAdd(Boolean.FALSE);
                userWalletDetailDao.insert(userWalletDetail);

            } else if (StrUtil.equals(result.getString("orderStatus"), "01")) {
                sandTransferRecord.setApprovalStatus(1);
                sandTransferRecord.setFeeAmount(result.getString("feeAmt"));
                sandTransferRecord.setWithdrawStatus(0);
                sandTransferRecord.updateById();
            } else if (StrUtil.equals(result.getString("orderStatus"), "02")) {
                sandTransferRecord.setApprovalStatus(1);
                sandTransferRecord.setFeeAmount(result.getString("feeAmt"));
                sandTransferRecord.setWithdrawStatus(2);
                sandTransferRecord.updateById();
                userWalletDao.transferFail(sandTransferRecord.getUserId(), sandTransferRecord.getAmount());
            }
        } else {
            sandTransferRecord.setRemark(result.getString("responseDesc"));
            sandTransferRecord.updateById();
            log.error("转账失败:" + result.getString("responseDesc"));
        }
    }


    /**
     * 解绑
     */
    public void unbindCard(UserInfo userInfo, Long id) {
        WithdrawBankCard withdrawBankCard = withdrawBankCardDao.getById(id);
        if (ObjectUtil.isNull(withdrawBankCard) || BooleanUtil.isFalse(withdrawBankCard.getStatus()) || withdrawBankCard.getUserId().longValue() != userInfo.getId().longValue()) {
            throw new GlobalRunTimeException("未找到该银行卡");
        }

        JSONObject param = new JSONObject();
        param.put("customerOrderNo", OrderNoUtil.getOrderNo()); //商户订单号 不能重复
        param.put("bizUserNo", userInfo.getSandWithdrawUuid()); //会员编号
        param.put("relatedCardNo", withdrawBankCard.getRelatedCardNo()); //关联卡编号
        JSONObject result = invoke(userInfo.getId(), param, SandMethodEnum.CEAS_ELEC_UNBIND_CARD);
        if (StrUtil.equals(result.getString("responseCode"), "00000")) {
            withdrawBankCard.setStatus(false);
            withdrawBankCard.updateById();
        } else {
            throw new GlobalRunTimeException("解绑失败:" + result.getString("responseDesc"));
        }
    }

    public void unbindCardAdmin(Long userId, String sandWithdrawUuid, String relatedCardNo) {
        JSONObject param = new JSONObject();
        param.put("customerOrderNo", OrderNoUtil.getOrderNo()); //商户订单号 不能重复
        param.put("bizUserNo", sandWithdrawUuid); //会员编号
        param.put("relatedCardNo", relatedCardNo); //关联卡编号
        JSONObject result = invoke(userId, param, SandMethodEnum.CEAS_ELEC_UNBIND_CARD);
        if (StrUtil.equals(result.getString("responseCode"), "00000")) {
            log.info("用户id:{},解绑成功", userId);
            log.info("用户id:{},解绑成功", userId);
            log.info("用户id:{},解绑成功", userId);
        } else {
            throw new GlobalRunTimeException("解绑失败:" + result.getString("responseDesc"));
        }
    }

    /**
     * 注销开户
     */
    public String cancel(UserInfo userInfo) {
        JSONObject param = new JSONObject();
        String orderNo = OrderNoUtil.getOrderNo();
        param.put("customerOrderNo", orderNo); //商户订单号
        param.put("bizUserNo", userInfo.getSandWithdrawUuid()); //会员编号
        param.put("bizType", "CLOSE"); //操作类型 CLOSE--销户 默认为销户（为之后冻结解冻功能预留）FREEZE-冻结会员 UNFREEZE-解冻会员
        param.put("frontUrl", SandConfig.FAST_RETURN_URL); //前台跳转地址
        param.put("notifyUrl", cancelNotify); //异步通知地址
        param.put("remark", "销户"); //备注 注销原因、备注 非必填
        JSONObject result = invoke(userInfo.getId(), param, SandMethodEnum.CEAS_ELEC_ACCOUNT_MEMBER_STATUS_MODIFY);
        if (StrUtil.equals(result.getString("responseCode"), "00000")) {
            return orderNo;
        } else {
            throw new GlobalRunTimeException("解绑失败:" + result.getString("responseDesc"));
        }
    }

    /**
     * 用户操作确认
     *
     * @return
     */
    public String affirm(UserInfo userInfo, UserAffirmDTO userAffirmDTO) {
        JSONObject param = new JSONObject();
        param.put("customerOrderNo", OrderNoUtil.getOrderNo()); //商户订单号
        param.put("bizUserNo", userInfo.getSandWithdrawUuid()); //会员编号
        param.put("oriCustomerOrderNo", userAffirmDTO.getOrderNo()); //原交易订单号
        param.put("smsCode", userAffirmDTO.getSmsCode()); //短信验证码
        param.put("notifyUrl", ""); //异步通知地址
        JSONObject result = invoke(userInfo.getId(), param, SandMethodEnum.CEAS_ELEC_ACCOUNT_MEMBER_MODIFY_CONFIRM);
        if (StrUtil.equals(result.getString("responseCode"), "00000")) {
            return result.getString("passwordURL");
        } else {
            throw new GlobalRunTimeException("解绑失败:" + result.getString("responseDesc"));
        }
    }

    /**
     * 设置支付密码
     */
    public String payPwd(UserInfo userInfo) {
        JSONObject param = new JSONObject();
        param.put("customerOrderNo", OrderNoUtil.getOrderNo()); //商户订单号 不能重复
        param.put("bizUserNo", userInfo.getSandWithdrawUuid()); //会员编号
        param.put("pageType", "01");
        param.put("managementType", "01");
        param.put("frontUrl", SandConfig.FAST_RETURN_URL);
        param.put("notifyUrl", pwdNotify);
        JSONObject result = invoke(userInfo.getId(), param, SandMethodEnum.CEAS_ELEC_ACCOUNT_PAY_PASSWORD_MANAGE);
        if (StrUtil.equals(result.getString("responseCode"), "00000")) {
            return result.getString("url");
        } else {
            throw new GlobalRunTimeException("解绑失败:" + result.getString("responseDesc"));
        }
    }

    public String setNewPhone(UserInfo userInfo) {
        JSONObject param = new JSONObject();
        param.put("customerOrderNo", OrderNoUtil.getOrderNo()); //商户订单号 不能重复
        param.put("bizUserNo", userInfo.getSandWithdrawUuid()); //会员编号
        param.put("pageType", "01");
        param.put("managementType", "03");
        param.put("frontUrl", SandConfig.FAST_RETURN_URL);
        param.put("notifyUrl", pwdNotify);
        JSONObject result = invoke(userInfo.getId(), param, SandMethodEnum.CEAS_ELEC_ACCOUNT_PAY_PASSWORD_MANAGE);
        if (StrUtil.equals(result.getString("responseCode"), "00000")) {
            return result.getString("url");
        } else {
            throw new GlobalRunTimeException("解绑失败:" + result.getString("responseDesc"));
        }
    }


    public String queryAccountDetail(UserInfo userInfo, String startDate, String endDate, String pageNo, String pageSize, Integer ioFlag) {
        JSONObject param = new JSONObject();
        param.put("customerOrderNo", OrderNoUtil.getOrderNo()); //商户订单号 不能重复
        param.put("bizUserNo", userInfo.getSandWithdrawUuid()); //会员编号
        param.put("accountType", "01");
        param.put("beginDate", startDate);
        param.put("endDate", endDate);
        if (null != ioFlag) {
            param.put("ioFlag", ioFlag == 0 ? "02" : "01");
        }
        param.put("pageNo", pageNo);
        param.put("pageSize", pageSize);
        JSONObject result = invoke(userInfo.getId(), param, SandMethodEnum.CEAS_ELEC_ACC_CHANGE_DETAILS);
        if (StrUtil.equals(result.getString("responseCode"), "00000")) {
            return result.toJSONString();
        } else {
            throw new GlobalRunTimeException("解绑失败:" + result.getString("responseDesc"));
        }
    }

    /**
     * 设置支付密码
     */
    public String payPwdH5(UserInfo userInfo) {
        JSONObject param = new JSONObject();
        param.put("customerOrderNo", OrderNoUtil.getOrderNo()); //商户订单号 不能重复
        param.put("bizUserNo", userInfo.getSandWithdrawUuid()); //会员编号
        param.put("pageType", "01");
        param.put("managementType", "01");
        param.put("frontUrl", walletUrl);
        param.put("notifyUrl", pwdNotify);
        JSONObject result = invoke(userInfo.getId(), param, SandMethodEnum.CEAS_ELEC_ACCOUNT_PAY_PASSWORD_MANAGE);
        if (StrUtil.equals(result.getString("responseCode"), "00000")) {
            return result.getString("url");
        } else {
            throw new GlobalRunTimeException("解绑失败:" + result.getString("responseDesc"));
        }
    }

    /**
     * 提现
     *
     * @param userInfo
     * @param withdrawBankCard
     * @param amount
     */
    public String withDraw(UserInfo userInfo, WithdrawBankCard withdrawBankCard, BigDecimal amount) {
        SandWithdrawRecord withdrawRecord = new SandWithdrawRecord();
        withdrawRecord.setUserId(userInfo.getId());
        withdrawRecord.setConfirmStatus(true);
        withdrawRecord.setSettleTime(DateTime.now());
        withdrawRecord.setCustomerOrderNo(OrderNoUtil.getOrderNo());
        withdrawRecord.setAmount(amount);
        String fee = staticDataDao.getByType("sand_withdrawal_fee").getValue();
        String minimumWithdrawalFee = staticDataDao.getByType("minimum_withdrawal_fee").getValue();
        BigDecimal feeAmount = amount.multiply(new BigDecimal(fee));
        feeAmount = feeAmount.compareTo(Convert.toBigDecimal(minimumWithdrawalFee)) > 0 ? feeAmount : Convert.toBigDecimal(minimumWithdrawalFee);

        withdrawRecord.setFeeAmount(feeAmount);
        withdrawRecord.setRealAmount(amount.subtract(withdrawRecord.getFeeAmount()));
        withdrawRecord.setRelatedCardNo(withdrawBankCard.getRelatedCardNo());
        withdrawRecord.setStatus(0);
        JSONObject param = new JSONObject();
        param.put("customerOrderNo", withdrawRecord.getCustomerOrderNo());//商户订单号
        param.put("bizUserNo", userInfo.getSandWithdrawUuid());//会员编号
        param.put("accountType", "01");//账户类型 01：支付电子户 02：宝易付权益电子户
        param.put("orderAmt", withdrawRecord.getAmount().toPlainString()); //订单金额
        param.put("relatedCardNo", withdrawRecord.getRelatedCardNo());//关联卡编号
        param.put("userFeeAmt", withdrawRecord.getFeeAmount().setScale(2, BigDecimal.ROUND_DOWN).stripTrailingZeros().toPlainString());//用户服务费
        param.put("notifyUrl", withdrawNotify); //异步通知地址
        param.put("frontUrl", SandConfig.FAST_RETURN_URL); //异步通知地址
        JSONObject result = invoke(userInfo.getId(), param, SandMethodEnum.CEAS_SERVER_WITHDRAW_APPLY);
        if (StrUtil.equals(result.getString("responseCode"), "00000")) {
            withdrawRecord.insert();
            return result.getString("passwordURL");
        } else {
            throw new GlobalRunTimeException("提现失败:" + result.getString("responseDesc"));
        }
    }

    /**
     * 查询衫德用户信息
     *
     * @param userInfo
     * @return
     */
    public String getSandInfo(UserInfo userInfo) {
        JSONObject param = new JSONObject();
        param.put("customerOrderNo", OrderNoUtil.getOrderNo()); //商户订单号 可以和关联卡订单号一致
        param.put("bizUserNo", userInfo.getSandWithdrawUuid()); //会员编号
        JSONObject result = invoke(userInfo.getId(), param, SandMethodEnum.CEAS_ELEC_MEMBER_INFO);
        return result.toJSONString();
    }

    /**
     * 查询余额
     *
     * @param userInfo
     * @return
     */
    public BalanceVO getBalance(UserInfo userInfo) {
        JSONObject param = new JSONObject();
        param.put("customerOrderNo", OrderNoUtil.getOrderNo()); //商户订单号 可以和关联卡订单号一致
        param.put("bizUserNo", userInfo.getSandWithdrawUuid()); //会员编号
        param.put("accountType", "01"); //账户类型 01：支付电子户 02：宝易付权益电子户 03：无资金权益户
        JSONObject result = invoke(userInfo.getId(), param, SandMethodEnum.CEAS_ELEC_QUERY_ACCOUNT_BALANCE);
        if (StrUtil.equals(result.getString("responseCode"), "00000")) {
            JSONObject account = result.getJSONArray("accountList").getJSONObject(0);
            BalanceVO balanceVO = new BalanceVO();
            balanceVO.setAvailableBal(account.getBigDecimal("availableBal"));
            balanceVO.setFrozenBal(account.getBigDecimal("frozenBal"));
            log.info("杉德查询结果返回对象：{},封装后返回：{}", result, JSONUtil.toJsonStr(balanceVO));
            return balanceVO;
        } else {
            throw new GlobalRunTimeException("查询余额失败:" + result.getString("responseDesc"));
        }
    }

    /**
     * 查询余额明细
     *
     * @param userInfo
     * @return
     */
    public BalanceVO getBalanceDetail(UserInfo userInfo, Integer pageNo, Integer pageSize, String ioFlag, Date StartTime, Date endTime) {
        JSONObject param = new JSONObject();
        param.put("customerOrderNo", OrderNoUtil.getOrderNo()); //商户订单号 可以和关联卡订单号一致
        param.put("bizUserNo", userInfo.getSandWithdrawUuid()); //会员编号
        param.put("accountType", "01"); //账户类型 01：支付电子户 02：宝易付权益电子户 03：无资金权益户
        JSONObject result = invoke(userInfo.getId(), param, SandMethodEnum.CEAS_ELEC_QUERY_ACCOUNT_BALANCE);
        if (StrUtil.equals(result.getString("responseCode"), "00000")) {
            JSONObject account = result.getJSONArray("accountList").getJSONObject(0);
            BalanceVO balanceVO = new BalanceVO();
            balanceVO.setAvailableBal(account.getBigDecimal("availableBal"));
            balanceVO.setFrozenBal(account.getBigDecimal("frozenBal"));
            return balanceVO;
        } else {
            throw new GlobalRunTimeException("查询余额失败:" + result.getString("responseDesc"));
        }
    }

    /**
     * 充值
     *
     * @param userInfo
     * @return
     */
    public String recharge(UserInfo userInfo, BigDecimal amount, String relatedCardNo) {
        Assert.isTrue(userInfo.getSandAccountOpen(), () -> new GlobalRunTimeException("您尚未完成衫德开户"));
        JSONObject param = new JSONObject();
        param.put("customerOrderNo", OrderNoUtil.getOrderNo()); //商户订单号
        param.put("bizUserNo", userInfo.getSandWithdrawUuid()); //会员编号
        param.put("orderTotalAmt", amount.toPlainString());
        param.put("payTool", "UNION_PAY_H5");
        param.put("walletAmt", amount.toPlainString());
        param.put("notifyUrl", rechargeNotify);
        param.put("frontUrl", SandConfig.FAST_RETURN_URL);
        JSONObject payExtend = new JSONObject();
        payExtend.put("relatedCardNo", relatedCardNo);
        param.put("payExtend", payExtend);
        JSONObject result = invoke(userInfo.getId(), param, SandMethodEnum.CEAS_SERVER_PAYMENT_DEPOSIT);
        if (StrUtil.equals(result.getString("responseCode"), "00000")) {
            return result.getJSONObject("payVoucher").getString("url");
        } else {
            throw new GlobalRunTimeException(result.getString("responseDesc"));
        }


    }


    private JSONObject invoke(Long userId, JSONObject param, SandMethodEnum sandMethodEnum) {
        JSONObject resp = null;
        SandBizRecord record = new SandBizRecord();
        record.setUserId(userId);
        if (sandMethodEnum != SandMethodEnum.CEAS_ELEC_PAPERS_UPLOAD) {
            record.setReqParams(param.toJSONString());
        }
        record.setMethodDesc(sandMethodEnum.getMethodDesc());
        record.setCustomerOrderNo(param.getString("customerOrderNo"));
        record.setBizMethod(sandMethodEnum.getMethodCode());
        resp = CeasHttpUtil.doPost(param, sandMethodEnum);
        record.setResult(resp.toJSONString());
        record.insert();
        log.info("响应报文：\n" + record.getResult());
        return resp;

    }


    /**
     * 附件上传编码方法
     *
     * @param img
     * @return
     */
    public static String GetImageStr(MultipartFile img) {// 将图片文件转化为字节数组字符串，并对其进行Base64编码处理
        byte[] data = null;

        // 读取图片字节数组
        try (InputStream in = img.getInputStream()) {
            data = new byte[in.available()];
            in.read(data);
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 对字节数组Base64编码
        BASE64Encoder encoder = new BASE64Encoder();
        return encoder.encode(data);// 返回Base64编码过的字节数组字符串
    }

}
